<?php

declare(strict_types=1);

namespace Zlf\AppValidateAnnotations;

use Zlf\AppException\Exception\ValidateException;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\Di\Aop\ProceedingJoinPoint;
use Hyperf\Di\Exception\Exception;
use Hyperf\HttpServer\Contract\RequestInterface;
use Zlf\AppValidate\ValidateAbstract;
use Hyperf\Context\Context;
use Psr\Http\Message\ServerRequestInterface;
use Zlf\AppValidate\Validate as ValidateData;
use function Hyperf\Support\make;

#[Aspect(priority: 80)]
class ValidateAspect extends AbstractAspect
{

    #[Inject]
    protected RequestInterface $request;

    /**
     * 要切入的注解
     * @var array
     */
    public array $annotations = [
        Validate::class
    ];


    /**
     * 验证器切片
     * @param ProceedingJoinPoint $proceedingJoinPoint
     * @return mixed
     * @throws Exception
     * @throws ValidateException
     * @throws \Zlf\AppException\Exception\ValidateException
     */
    public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
    {
        /**
         * @var Validate $annotation
         */
        $annotation = $proceedingJoinPoint->getAnnotationMetadata()->method[Validate::class] ?? null;
        if (is_null($annotation)) return $proceedingJoinPoint->process();//未配置验证器注解,理论上这个不可能出现
        if ($annotation->method !== $this->request->getMethod()) {
            return $proceedingJoinPoint->process();//请求方式不符合要求
        }
        $data = $this->request->all();
        if (count($annotation->rules) > 0) {//规则验证
            $validate = new ValidateData();
            $validate->setRules($annotation->rules);
            $validate->setLabels($annotation->labels);
        } elseif ($annotation->class) {//类验证
            /**
             * @var ValidateAbstract $validate
             */
            $validate = make($annotation->class);
        } else {
            throw new ValidateException('验证规则错误');
        }
        $validate->setData($data);
        if ($annotation->fields) {
            $validate->setFields($annotation->fields);
        } elseif (gettype($annotation->scene) === 'string' && strlen($annotation->scene) > 0) {//设置场景
            $validate->setScene($annotation->scene);
        }
        $validate->validate();
        if ($validate->isFail()) {
            throw new ValidateException($validate->firstError());
        }
        $safeData = $validate->getSafeData(); //验证通过的安全数据
        Context::override(ServerRequestInterface::class, function (ServerRequestInterface $request) use ($safeData) {
            return $request->withParsedBody($safeData);
        });
        return $proceedingJoinPoint->process();
    }
}